package com.atguigu.tingshu.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.BusinessException;
import com.atguigu.tingshu.common.kafka.constant.KafkaConst;
import com.atguigu.tingshu.common.kafka.service.KafkaService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.utils.ThrowUtil;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserPaidAlbum;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.user.service.UserPaidAlbumService;
import com.atguigu.tingshu.user.service.UserPaidTrackService;
import com.atguigu.tingshu.user.service.UserVipServiceService;
import com.atguigu.tingshu.user.service.VipServiceConfigService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.atguigu.tingshu.vo.user.UserUpdateVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({ "all" })
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private KafkaService kafkaService;

    @Autowired
    private UserPaidTrackService userPaidTrackService;

    @Autowired
    private UserPaidAlbumMapper userPaidAlbumMapper;

    @Autowired
    private VipServiceConfigService vipServiceConfigService;

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private UserPaidAlbumService userPaidAlbumService;

    @Autowired
    private UserVipServiceService userVipServiceService;

    @Override
    public Map<String, Object> wxLogin(String code) {
        try {
            // 1. 使用 code 换取 openid 和 session_key
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
            String openid = sessionInfo.getOpenid();

            if (!StringUtils.hasText(openid)) {
                log.error("微信登录失败，无法获取 openid");
                throw new BusinessException(ResultCodeEnum.LOGIN_AUTH);
            }

            log.info("微信登录，获取到 openid: {}", openid);

            // 2. 根据 openid 查询用户是否存在
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserInfo::getWxOpenId, openid);
            UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);

            // 3. 判断是否是新用户
            boolean isNew = false;
            if (userInfo == null) {
                // 新用户，创建用户信息
                isNew = true;
                userInfo = new UserInfo();
                userInfo.setWxOpenId(openid);
                userInfo.setNickname("微信用户");
                userInfo.setAvatarUrl("");
                userInfo.setIsVip(0);
                userInfo.setStatus("1");
                userInfoMapper.insert(userInfo);
                log.info("新用户注册成功，openid: {}, userId: {}", openid, userInfo.getId());

                // 发送用户注册消息到 Kafka，用于账户初始化
                try {
                    Map<String, Object> registerMessage = new HashMap<>();
                    registerMessage.put("userId", userInfo.getId());
                    registerMessage.put("nickname", userInfo.getNickname());
                    registerMessage.put("wxOpenId", openid);

                    kafkaService.sendMessage(KafkaConst.TOPIC_USER_REGISTER, registerMessage);
                    log.info("用户注册消息已发送到 Kafka - userId: {}", userInfo.getId());
                } catch (Exception e) {
                    log.error("发送用户注册消息失败，userId: {}", userInfo.getId(), e);
                    // 注意：这里不抛出异常，避免影响用户注册流程
                }
            } else {
                log.info("老用户登录，userId: {}", userInfo.getId());
            }

            // 4. 生成 token 并存入 Redis
            String token = UUID.randomUUID().toString().replaceAll("-", "");
            String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;

            // 将用户 ID 存入 Redis，设置过期时间
            redisTemplate.opsForValue().set(
                    loginKey,
                    userInfo.getId().toString(),
                    RedisConstant.USER_LOGIN_KEY_TIMEOUT,
                    TimeUnit.SECONDS);

            log.info("用户登录成功，token: {}, userId: {}", token, userInfo.getId());

            // 5. 构建返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("isNew", isNew);

            // 构建用户信息 VO
            UserInfoVo userInfoVo = new UserInfoVo();
            BeanUtils.copyProperties(userInfo, userInfoVo);
            result.put("userInfo", userInfoVo);

            return result;

        } catch (Exception e) {
            log.error("微信登录异常", e);
            throw new BusinessException(ResultCodeEnum.LOGIN_AUTH);
        }
    }

    /**
     * @param @param id
     * @return @return {@code UserInfoVo }
     * @name getUserInfo
     * @description 获取用户信息（根据id）
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {
        ThrowUtil.throwIf(userId == null, ResultCodeEnum.LOGIN_AUTH);
        // 1. 构建用户信息缓存 key
        String userInfoCacheKey = RedisConstant.CACHE_INFO_PREFIX + "userInfo:" + userId;
        // 2. 先从 Redis 缓存中获取用户信息
        String userInfoJson = redisTemplate.opsForValue().get(userInfoCacheKey);
        if (StringUtils.hasText(userInfoJson)) {
            log.info("从缓存中获取用户信息，userId: {}", userId);
            UserInfoVo userInfoVo = JSON.parseObject(userInfoJson, UserInfoVo.class);
            return userInfoVo;
        }
        // 3. 缓存中没有，从数据库查询
        log.info("缓存未命中，从数据库查询用户信息，userId: {}", userId);
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo == null) {
            log.error("用户不存在，userId: {}", userId);
            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
        }
        // 4. 构建用户信息 VO
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);
        // 5. 将用户信息存入 Redis 缓存，设置过期时间为 1 小时
        redisTemplate.opsForValue().set(
                userInfoCacheKey,
                JSON.toJSONString(userInfoVo),
                RedisConstant.CACHE_TIMEOUT,
                TimeUnit.SECONDS);
        log.info("用户信息已缓存，userId: {}", userId);
        return userInfoVo;
    }

    @Override
    public boolean updateUser(UserUpdateVo userUpdateVo) {
        try {
            // 1. 参数校验
            ThrowUtil.throwIf(userUpdateVo == null, ResultCodeEnum.DATA_ERROR,
                    "更新用户信息失败，数据为为空");
            ThrowUtil.throwIf(userUpdateVo.getId() == null, ResultCodeEnum.DATA_ERROR,
                    "用户ID不能为空");

            Long userId = userUpdateVo.getId();
            log.info("开始更新用户信息，userId: {}", userId);

            // 2. 先更新数据库
            UserInfo userInfo = new UserInfo();
            userInfo.setId(userId);
            BeanUtils.copyProperties(userUpdateVo, userInfo);

            // 执行数据库更新
            boolean updateResult = this.updateById(userInfo);
            ThrowUtil.throwIf(!updateResult, ResultCodeEnum.SERVICE_ERROR, "更新用户信息失败");
            log.info("用户信息数据库更新成功，userId: {}", userId);

            // 3. 删除缓存，保证数据库缓存的一致性
            String userInfoCacheKey = RedisConstant.CACHE_INFO_PREFIX + "userInfo:" + userId;
            Boolean deleteResult = redisTemplate.delete(userInfoCacheKey);
            return true;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("更新用户信息异常，userId: {}", userUpdateVo != null ? userUpdateVo.getId() : null, e);
            throw new BusinessException(ResultCodeEnum.SERVICE_ERROR);
        }
    }

    /**
     * 获取用户声音列表付费情况
     *
     * @param userId                    用户ID
     * @param albumId                   专辑ID
     * @param needCheckBuyStateTrackIds 需要检查购买状态的声音ID列表
     * @return 声音ID与付费状态的映射，1表示已购买，0表示未购买
     */
    @Override
    public Map<Long, Integer> getUserTrackPaidState(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds) {
        // 1. 参数校验
        ThrowUtil.throwIf(userId == null, "用户ID不能为空");
        ThrowUtil.throwIf(albumId == null, "专辑ID不能为空");
        ThrowUtil.throwIf(needCheckBuyStateTrackIds == null || needCheckBuyStateTrackIds.isEmpty(),
                "需要检查的声音ID列表不能为空");
        // 2. 查询用户购买过的所有声音列表（该专辑下的）
        LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPaidTrack::getUserId, userId)
                .eq(UserPaidTrack::getAlbumId, albumId)
                .select(UserPaidTrack::getTrackId);
        List<UserPaidTrack> userPaidTracks = userPaidTrackService.list(queryWrapper);
        // 3. 将用户已购买的声音ID转换为HashSet，提升查询效率（O(1)）
        Set<Long> paidTrackIdSet = userPaidTracks.stream()
                .map(UserPaidTrack::getTrackId)
                .collect(Collectors.toSet());
        // 4. 构建返回结果：需要检查的声音ID与付费状态的映射
        Map<Long, Integer> paidStateMap = new HashMap<>();
        for (Long trackId : needCheckBuyStateTrackIds) {
            // 使用HashSet的contains方法，时间复杂度O(1)
            paidStateMap.put(trackId, paidTrackIdSet.contains(trackId) ? 1 : 0);
        }
        log.info("获取用户声音付费情况 - userId: {}, albumId: {}, 检查数量: {}, 已购数量: {}",
                userId, albumId, needCheckBuyStateTrackIds.size(),
                paidStateMap.values().stream().filter(v -> v == 1).count());
        return paidStateMap;
    }

    @Override
    public Boolean isPaidAlbum(Long albumId) {
        // 从 ThreadLocal 中获取当前登录用户ID
        Long userId = AuthContextHolder.getUserId();
        log.info("判断用户是否购买过专辑 - userId: {}, albumId: {}", userId, albumId);

        // 参数校验
        ThrowUtil.throwIf(albumId == null, "专辑ID不能为空");

        // 查询用户是否购买过该专辑
        LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPaidAlbum::getUserId, userId)
                .eq(UserPaidAlbum::getAlbumId, albumId);
        Long count = userPaidAlbumMapper.selectCount(queryWrapper);

        boolean isPaid = count > 0;
        log.info("用户专辑购买状态 - userId: {}, albumId: {}, isPaid: {}", userId, albumId, isPaid);
        return isPaid;
    }

    @Override
    public Boolean isPaidTrack(List<Long> trackIdList) {
        // 从 ThreadLocal 中获取当前登录用户ID
        Long userId = AuthContextHolder.getUserId();
        log.info("判断用户是否购买过声音列表 - userId: {}, trackIdList size: {}", userId,
                trackIdList != null ? trackIdList.size() : 0);

        // 参数校验
        ThrowUtil.throwIf(trackIdList == null || trackIdList.isEmpty(), "声音ID列表不能为空");

        // 查询用户是否购买过列表中的任意一个声音
        LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserPaidTrack::getUserId, userId)
                .in(UserPaidTrack::getTrackId, trackIdList)
                .last("LIMIT 1"); // 只需要查询一条记录即可
        Long count = userPaidTrackService.count(queryWrapper);

        boolean isPaid = count > 0;
        log.info("用户声音购买状态 - userId: {}, 检查数量: {}, 是否购买: {}", userId, trackIdList.size(), isPaid);
        return isPaid;
    }

    @Override
    public void savePaidRecord(UserPaidRecordVo userPaidRecordVo) {
        //TODO 2025/11/21 策略模式优化
        // 参数校验
        ThrowUtil.throwIf(userPaidRecordVo == null, "购买记录信息不能为空");
        ThrowUtil.throwIf(userPaidRecordVo.getUserId() == null, "用户ID不能为空");
        ThrowUtil.throwIf(!StringUtils.hasText(userPaidRecordVo.getOrderNo()), "订单号不能为空");
        ThrowUtil.throwIf(!StringUtils.hasText(userPaidRecordVo.getItemType()), "付款项目类型不能为空");
        ThrowUtil.throwIf(userPaidRecordVo.getItemIdList() == null || userPaidRecordVo.getItemIdList().isEmpty(),
                "购买项ID列表不能为空");
        String orderNo = userPaidRecordVo.getOrderNo();
        Long userId = userPaidRecordVo.getUserId();
        String itemType = userPaidRecordVo.getItemType();
        List<Long> itemIdList = userPaidRecordVo.getItemIdList();
        log.info("保存用户购买记录 - userId: {}, orderNo: {}, itemType: {}, itemIdList: {}",
                userId, orderNo, itemType, itemIdList);
        // 根据订单号判断是否已处理过
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(itemType)) {
            // 专辑购买，itemIdList中就是专辑ID列表
            LambdaQueryWrapper<UserPaidAlbum> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserPaidAlbum::getOrderNo, orderNo).last("LIMIT 1");
            Long count = userPaidAlbumMapper.selectCount(queryWrapper);
            if (count > 0) {
                log.info("订单已处理过，无需重复处理 - orderNo: {}", orderNo);
                return;
            }
            // 批量插入专辑购买记录
            List<UserPaidAlbum> userPaidAlbumList = itemIdList.stream().map(albumId -> {
                UserPaidAlbum userPaidAlbum = new UserPaidAlbum();
                userPaidAlbum.setOrderNo(orderNo);
                userPaidAlbum.setUserId(userId);
                userPaidAlbum.setAlbumId(albumId);
                return userPaidAlbum;
            }).collect(Collectors.toList());
            userPaidAlbumService.saveBatch(userPaidAlbumList);
            log.info("专辑购买记录保存成功 - orderNo: {}, 数量: {}", orderNo, userPaidAlbumList.size());
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(itemType)) {
            // 声音购买，itemIdList中是声音ID列表，需要通过Feign获取专辑ID
            LambdaQueryWrapper<UserPaidTrack> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserPaidTrack::getOrderNo, orderNo).last("LIMIT 1");
            Long count = userPaidTrackService.count(queryWrapper);
            if (count > 0) {
                log.info("订单已处理过，无需重复处理 - orderNo: {}", orderNo);
                return;
            }
            // 调用Feign接口获取专辑ID映射
            Result<Map<Long, Long>> albumIdsResult = albumFeignClient.getAlbumIdsByTrackIds(itemIdList);
            ThrowUtil.throwIf(albumIdsResult == null || albumIdsResult.getData() == null,
                    "获取声音专辑ID失败");
            Map<Long, Long> trackAlbumMap = albumIdsResult.getData();
            // 批量插入声音购买记录
            List<UserPaidTrack> userPaidTrackList = itemIdList.stream().map(trackId -> {
                UserPaidTrack userPaidTrack = new UserPaidTrack();
                userPaidTrack.setOrderNo(orderNo);
                userPaidTrack.setUserId(userId);
                userPaidTrack.setAlbumId(trackAlbumMap.get(trackId));
                userPaidTrack.setTrackId(trackId);
                return userPaidTrack;
            }).collect(Collectors.toList());
            userPaidTrackService.saveBatch(userPaidTrackList);
            log.info("声音购买记录保存成功 - orderNo: {}, 数量: {}", orderNo, userPaidTrackList.size());
        } else if (SystemConstant.ORDER_ITEM_TYPE_VIP.equals(itemType)) {
            // VIP购买，先从user_vip_service表查询订单号是否已处理
            LambdaQueryWrapper<com.atguigu.tingshu.model.user.UserVipService> vipQueryWrapper = new LambdaQueryWrapper<>();
            vipQueryWrapper.eq(com.atguigu.tingshu.model.user.UserVipService::getOrderNo, orderNo).last("LIMIT 1");
            Long vipCount = userVipServiceService.count(vipQueryWrapper);
            if (vipCount > 0) {
                log.info("VIP订单已处理过，无需重复处理 - orderNo: {}", orderNo);
                return;
            }
            // 获取VIP配置信息
            ThrowUtil.throwIf(itemIdList.size() != 1, "VIP购买记录项ID列表应只包含一个VIP配置ID");
            Long vipConfigId = itemIdList.get(0);
            VipServiceConfig vipServiceConfig = vipServiceConfigService.getVipServiceConfigById(vipConfigId);
            ThrowUtil.throwIf(vipServiceConfig == null, "VIP配置不存在");
            Integer serviceMonth = vipServiceConfig.getServiceMonth();
            ThrowUtil.throwIf(serviceMonth == null || serviceMonth <= 0, "VIP服务月数配置错误");
            // 查询用户当前信息
            UserInfo userInfo = userInfoMapper.selectById(userId);
            ThrowUtil.throwIf(userInfo == null, "用户不存在");
            // 计算VIP过期时间
            Date newVipExpireTime;
            Date startTime;
            if (userInfo.getIsVip() != null && userInfo.getIsVip() == 1
                    && userInfo.getVipExpireTime() != null
                    && userInfo.getVipExpireTime().after(new Date())) {
                // 已是VIP且未过期，延长VIP时间
                startTime = userInfo.getVipExpireTime();
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(userInfo.getVipExpireTime());
                calendar.add(Calendar.MONTH, serviceMonth);
                newVipExpireTime = calendar.getTime();
                log.info("延长VIP时间 - userId: {}, 原过期时间: {}, 新过期时间: {}",
                        userId, userInfo.getVipExpireTime(), newVipExpireTime);
            } else {
                // 不是VIP或已过期，设置为VIP并设置过期时间
                startTime = new Date();
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.MONTH, serviceMonth);
                newVipExpireTime = calendar.getTime();
                log.info("设置为VIP用户 - userId: {}, 过期时间: {}", userId, newVipExpireTime);
            }
            // 更新用户VIP信息
            UserInfo updateUserInfo = new UserInfo();
            updateUserInfo.setId(userId);
            updateUserInfo.setIsVip(1);
            updateUserInfo.setVipExpireTime(newVipExpireTime);
            userInfoMapper.updateById(updateUserInfo);
            // 保存VIP服务记录到user_vip_service表
            com.atguigu.tingshu.model.user.UserVipService userVipService = new com.atguigu.tingshu.model.user.UserVipService();
            userVipService.setOrderNo(orderNo);
            userVipService.setUserId(userId);
            userVipService.setStartTime(startTime);
            userVipService.setExpireTime(newVipExpireTime);
            userVipService.setIsAutoRenew(0); // 默认不自动续费
            userVipServiceService.save(userVipService);
            // 删除用户信息缓存
            String userInfoCacheKey = RedisConstant.CACHE_INFO_PREFIX + "userInfo:" + userId;
            redisTemplate.delete(userInfoCacheKey);
            log.info("VIP购买记录保存成功 - orderNo: {}, userId: {}, 过期时间: {}",
                    orderNo, userId, newVipExpireTime);
        } else {
            throw new BusinessException(ResultCodeEnum.DATA_ERROR, "未知的付款项目类型: " + itemType);
        }
    }
}
